"""
    Events Module. 
    
    Handles
        - Event Handlers
        - State creating and sharing        
        - Event objects
        - Hiding and wrapping of GLUT Event constants
"""

import time
from core import memoize, abstract
from OpenGL.GLUT import *
from types import Vector2

# Key definitions
ESCAPE = '\033'

class State(object):
    """ Holds data to be shared among event handlers """
    def __init__(self):
        pass
    
    @staticmethod
    def Create(**kwargs):
        """
            Creates a State object with given keyword arguments as properties.
            Reduces the need to subclass State
        """
        state = State()
        for k, v in kwargs.items():
            state.__dict__[k] = v
        return state

###
### Event Types
###     These are implemented as classes to allow control over which 
###     parameters are passed in and are used
###
###     Mouse button state is memoized
###


@memoize
class _MouseButton:
    __slots__ = ('_button', '_state')
    """ Represent mouse states. Since it is memoized, do not edit these instances """
    def __init__(self, button, state):
        self._button = button
        self._state = state
        
    @property
    def left(self):     return self._button == GLUT_LEFT_BUTTON
    
    @property
    def right(self):    return self._button == GLUT_RIGHT_BUTTON
    
    @property
    def up(self):       return self._state == GLUT_UP
    
    @property
    def down(self):     return self._state == GLUT_DOWN

class Event(object):
    def __init__(self, **kwargs):
        pass

class Render(Event):
    __slots__ = ('timedelta')
    def __init__(self, timedelta):
        self.timedelta = timedelta
        
class _BaseMouseEvent(Event):
    __slots__ = tuple(['position'])
    ''' Keeps common attributes for all mouse events. do not instantiate '''
    def __init__(self, **kwargs):
        setattr(self, 'position', Vector2(kwargs['cursor_x'], kwargs['cursor_y']))
    
class MouseClick(_BaseMouseEvent):
    __slots__ = _BaseMouseEvent.__slots__ + tuple(['button'])
    def __init__(self, **kwargs):
        setattr(self, 'button', _MouseButton(kwargs['button'], kwargs['button_state']))
        super(self.__class__, self).__init__(**kwargs)
        
class MouseMove(_BaseMouseEvent):
    __slots__ = _BaseMouseEvent.__slots__
    def __init__(self, **kwargs):
        super(self.__class__, self).__init__(**kwargs)
    
class WindowResize(Event):
    __slots__ = ('width', 'height')
    def __init__(self, **kwargs):
        super(self.__class__, self).__init__(**kwargs)
        setattr(self, 'width', kwargs['width'])
        setattr(self, 'height', kwargs['height'])

class KeyPress(Event):
    __slots__ = tuple(['key'])
    def __init__(self, **kwargs):
        setattr(self, 'key', kwargs['key'])

class KeyUp(KeyPress):
    pass
        
###
### Event Handler Class
###
class Handler():
    """
        Generic Event Handler Class
    """
    def __init__(self, type, name = None, state = None):
        """
            Creates a Handler for a particular event type. Pass in the event class
            e.g. type= MouseDown for a mouse down event handler
        """
        
        if name is None: self.name = time.clock
        else: self.name = name
        self.state = state
        self._Event_class = type
        self._fn = lambda self, e: None         # used only for anonymously created functions
    
    def _fire(self, **kwargs):
        """ Creates an event object and then calls the handler, passing the event object """
        e = self._Event_class(**kwargs)
        self.call(e)
    
    def call(self, event):
        """ If you are creating a handler by subclassing, you need to override this"""
        self._fn(self, event)
    
    @property
    def state(self):
        return self.state
    
    @staticmethod
    def Create(type, fn, name = None, state = None):
        """
            Creates a Handler, pass in the handler function and type
        """
        handler = Handler(type, name, state)
        handler._fn = fn
        return handler
        
###
### Default Handlers
###

def fExitOnEscapeKey(self, event):       
    if event.key == ESCAPE:
        sys.exit()

ExitOnEscapeKey = Handler.Create(KeyPress, fExitOnEscapeKey)
